/*
 * Copyright 2008 Jeff Dwyer
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package edu.rpi.bt.server.service.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.annotation.Transactional;

import com.apress.progwt.client.domain.Loadable;
import com.apress.progwt.client.domain.User;
import com.apress.progwt.client.domain.commands.CommandService;
import com.apress.progwt.client.domain.commands.SiteCommand;
import com.apress.progwt.client.exception.SiteException;
import com.apress.progwt.server.service.SearchService;
import com.apress.progwt.server.service.UserService;
import com.apress.progwt.server.util.HTMLInputFilter;

import edu.rpi.bt.client.domain.Comment;
import edu.rpi.bt.client.domain.Destination;
import edu.rpi.bt.server.dao.DestinationDAO;
import edu.rpi.bt.server.dao.FlickrSearch;
import edu.rpi.bt.server.service.DestinationService;
/**
 * 
 * @author Ashoo
 * 
 *         
 */
@Transactional
public class DestinationServiceImpl implements DestinationService, CommandService {

    private static final HTMLInputFilter htmlFilter = new HTMLInputFilter();

    private static final Logger log = Logger
            .getLogger(DestinationServiceImpl.class);

    private DestinationDAO destinationDAO;
    private SearchService searchService;
    private UserService userService;

    public void assertUserIsAuthenticated(User toCheck)
            throws SecurityException {
        User loggedIn = userService.getCurrentUser();
        if (loggedIn == null || !loggedIn.equals(toCheck)) {
            throw new SecurityException("Logged in: " + loggedIn
                    + " Requested: " + toCheck);
        }
    }

    public void delete(Loadable loadable) {
        destinationDAO.delete(loadable);
    }

    public String escapeHtml(String string) {
        return StringEscapeUtils.escapeHtml(string);
    }

    public SiteCommand executeAndSaveCommand(SiteCommand command)
            throws SiteException {
        return executeAndSaveCommand(command, true);
    }

    /**
     * Can turn off the userCache which avoid some problems with our
     * transactional testing.
     */
    public SiteCommand executeAndSaveCommand(SiteCommand command,
            boolean useUserCache) throws SiteException {
//System.out.println("inexecuteandsave");

        User loggedIn = userService.getCurrentUser(useUserCache);
//System.out.println("User id " + loggedIn.getId());
if (loggedIn == null) {
    log.warn(command + " attempted by anonymous ");
  //  System.out.println("attempted by anonymous");
}

/*
        if (loggedIn == null) {
            log.warn(command + " attempted by anonymous ");
        }

        if (!command.haveYouSecuredYourselfAndFilteredUserInput()) {
            throw new BusinessException("Command " + command
                    + " hasn't secured.");
        }
        if (!userService.getToken(loggedIn).equals(command.getToken())) {
            log.warn("Possible XSRF: |" + command.getToken()
                    + "| expected |" + userService.getToken(loggedIn)
                    + "|");
            throw new SiteSecurityException("Invalid Session "
                    + command.getToken());
        } else {
            log.info("Tokens equal: " + userService.getToken(loggedIn));
        }
        if (loggedIn != null) {
            log.info(command + " " + loggedIn.getUsername());
        }
        */
 //       System.out.println("Going to execute Command...");
        log.info("Going to execute Command...");

        command.execute(this);
   //     System.out.println("Executed Command. Saving...");
        log.info("Executed Command. Saving...");

        return command;
    }

    public String filterHTML(String input) {
        return htmlFilter.filter(input);
    }

    public <T> T get(Class<T> clazz, long id) {
        return (T) destinationDAO.get((Class<? extends Loadable>) clazz, id);

    }

    public List<Destination> getAllDestinations() {
     //   System.out.println("Destnation service..In get add destinations");
        User user = userService.getCurrentUser();
   //     System.out.println("User nickname is " + user.getNickname());
        
        List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
        
        List<Destination> trip =new ArrayList();
        for (Iterator it = dests.iterator(); it.hasNext(); ) {
            Destination destination = (Destination)it.next();
            if((destination.getUser().equals(user)) && destination.getParent()==null){
                trip.add(destination);
                           }
            
         }
       // System.out.println("Destnation service...trips " + trip.size());
        //return  destinationDAO.getAllDestinationsByUserID(user); 
    return trip;
    }
    
    public List<Destination> getAllLocations() {
        //System.out.println("Destnation service..In get add destinations");
        User user = userService.getCurrentUser();
   //     System.out.println("User nickname is " + user.getNickname());
        
        List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
        
        List<Destination> locations =new ArrayList();
      
        for (Iterator it = dests.iterator(); it.hasNext(); ) {
            Destination destination = (Destination)it.next();
            if(locations.size() < 5){
            if( destination.getParent()!=null){
                
              
                    String n=destination.getName();
                    n.replaceAll(" +", " OR ");
          //          System.out.println("Location name... " + destination.getName() );
                    FlickrSearch f=new FlickrSearch(n, 1);
                    String[] u=f.getURLs();
                    if (u[0] !=null){
                   //     destination.setIURL(u[0]);
                        destination.setUstring(u[0]);
                 //       destination.setCity(u[0]); //Ashoo: I am piggybacking on this for now..since image is having weird problems on freemarker
                     
                    }else{
                //        destination.setIURL("http://farm2.static.flickr.com/1194/529356033_dbdae392d2_m.jpg");
                   //     destination.setCity("http://farm2.static.flickr.com/1194/529356033_dbdae392d2_m.jpg");
                    destination.setUstring("http://farm2.static.flickr.com/1194/529356033_dbdae392d2_m.jpg");
                    }
                    
            //        System.out.println("location..image" + destination.getCity());
                    locations.add(destination);
                }
                
            }
         }
        //System.out.println("size...trips " + locations.size());
        //return  destinationDAO.getAllDestinationsByUserID(user); 
    return locations;
    }
    
    
    public List<Destination> getTrips() {
        //System.out.println("Destnation service..In get add destinations");
        User user = userService.getCurrentUser();
   //     System.out.println("User nickname is " + user.getNickname());
        
        List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
        
        List<Destination> trips =new ArrayList();
       
        for (Iterator it = dests.iterator(); it.hasNext(); ) {
            Destination destination = (Destination)it.next();
           if(trips.size() < 10){
            if( destination.getParent()==null){
                trips.add(destination);
        //        System.out.println("my trip size " + trips.size());
                           }
            
        }
         }
        //System.out.println("Destnation service...trips " + trips.size());
        //return  destinationDAO.getAllDestinationsByUserID(user); 
    return trips;
    }
    
    
    
    
    public List<Destination> getAllTrips() {
     //   System.out.println("Trip service..In get add trips");
        User user = userService.getCurrentUser();
   //     System.out.println("User nickname is " + user.getNickname());
        
        List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
        
        List<Destination> trip =new ArrayList();
        for (Iterator it = dests.iterator(); it.hasNext(); ) {
            Destination destination = (Destination)it.next();
            if((destination.getUser().equals(user)) && destination.getParent()==null){
                trip.add(destination);
                           }
            
         }
       // System.out.println("Trip service...trips " + trip.size());
        //return  destinationDAO.getAllDestinationsByUserID(user); 
    return trip;
    }
    
    
    public List<Destination> getAllLocations(long tripId) {
    //    System.out.println("Location service..In get add locations...tripid " + tripId);
        User user = userService.getCurrentUser();
      //  System.out.println("Location service...User nickname is " + user.getNickname());
        
        List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
        //System.out.println("Location service...dests " + dests.size());
        
        List<Destination> locations =new ArrayList();
//        System.out.println("Location service...locs 0 " + locations.size());
        
        for (Iterator it = dests.iterator(); it.hasNext(); ) {
  //          System.out.println("Location service...locs 1 " );
            
            Destination destination = (Destination)it.next();
    //        System.out.println("Location service...dest is " + destination.getName() + " user " + destination.getUser().getNickname());
            if(destination.getParent()!=null){
      //      System.out.println("location parent is " + destination.getParent().getId());
            
            }else{
        //        System.out.println("No parent");
            }
            if((destination.getUser().equals(user))&& destination.getParent()!=null && destination.getParent().getId()==tripId){
          //      System.out.println("Location service...locs 3 " );
                
                locations.add(destination);
            //    System.out.println("Location service...locs 4 " + locations.size());
                           }
            
         }
        //System.out.println("location service...locations " + locations.size());
        //return  destinationDAO.getAllDestinationsByUserID(user); 
    return locations;
    }
    
    public List<Destination> getAllLocations(double lat, double lon){
        //  public List<Destination> getAllLocations(double lat, double lon) {
              //System.out.println("Location service lat long..In get add locations..ne.. " + minLat..toString() + "..sw.." + sw.toString() );
              
            //  BoundingBox bb=new BoundingBox(minLat, minLon, maxLat, maxLon);
          //    System.out.println("Location service lat ...");
              List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
            //  System.out.println("Location service...dests " + dests.size());
              
              return dests;
    }
    
    public List<Destination> getAllLocations(double lat, double lon, double lata, double lona){
        //  public List<Destination> getAllLocations(double lat, double lon) {
              //System.out.println("Location service lat long..In get add locations..ne.. " + minLat..toString() + "..sw.." + sw.toString() );
     //   System.out.println("Location service lat long..In get add locations..lat.. " + lat + "..lon.." + lon + "..lat a.." + lata + "..lon a.." + lona );
   //     BoundingBox bb=new BoundingBox(lat, lon, lata, lona);
           //   BoundingBox bb=new BoundingBox(minLat, minLon, maxLat, maxLon);
       //       System.out.println("Location service lat ...");
              List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
         //     System.out.println("Location service...dests " + dests.size());
              List<Destination> locations =new ArrayList();
              for (Iterator it = dests.iterator(); it.hasNext(); ) {
           //       System.out.println("Location service...locs 1 " );
                  
                  Destination destination = (Destination)it.next();
               
                 
                  if( destination.getParent()!=null  ){
             //         System.out.println("Location service...locs 2 ..lat " + destination.getLatitude() + "..long.." + destination.getLongitude());
          
                      
                      if (destination.getLatitude() != 0 && destination.getLongitude() !=0){
               //           System.out.println("Location service...locs 3 " );
                        if((  destination.getLatitude() > (lat) && destination.getLatitude() < (lata)) && (  destination.getLongitude() > (lon) &&  destination.getLongitude() < (lona))){
                            
                      
                          locations.add(destination);  
                      
                      // System.out.println("Location service...locs 4 " + locations.size());
                                  }
                      }
                  }
                   
                }
               //System.out.println("location service...locations " + locations.size());
               //return  destinationDAO.getAllDestinationsByUserID(user); 
           return locations;
                      
          //    return dests;
    }
    /*
    public List<Destination> getAllLocations(double minLat, double minLon, double maxLat, double maxLon){
  //  public List<Destination> getAllLocations(double lat, double lon) {
        //System.out.println("Location service lat long..In get add locations..ne.. " + minLat..toString() + "..sw.." + sw.toString() );
        
        BoundingBox bb=new BoundingBox(minLat, minLon, maxLat, maxLon);
        System.out.println("Location service lat ..."+ bb.toString());
        List<Destination> dests= destinationDAO.getAllDestinations(0, 2500);
        System.out.println("Location service...dests " + dests.size());
        
        List<Destination> locations =new ArrayList();
        System.out.println("Location service...locs 0 " + locations.size());
        
        for (Iterator it = dests.iterator(); it.hasNext(); ) {
            System.out.println("Location service...locs 1 " );
            
            Destination destination = (Destination)it.next();
         
           
            if( destination.getParent()==null  ){
                System.out.println("Location service...locs 2 ..lat " + destination.getLatitude() + "..long.." + destination.getLongitude());
            */
             /*   
                double v=destination.getLatitude();
                if (v != 0 && destination.getLongitude() !=0){
                    System.out.println("Location service...locs 3 " );
                  if((  destination.getLatitude() > (lat-10) || destination.getLatitude() < (lat+10)) && (  destination.getLongitude() > (lon-10) ||  destination.getLongitude() < (lon+10))){
                      
                      locations.add(destination);  
                  }
                }
               */
            /*    
               if(bb.contains( new LatLonPoint( destination.getLatitude(),destination.getLongitude() ))){
                   locations.add(destination);  
               }
              
                System.out.println("Location service...locs 4 " + locations.size());
                           }
            
         }
        System.out.println("location service...locations " + locations.size());
        //return  destinationDAO.getAllDestinationsByUserID(user); 
    return locations;
        
    }
    */
    
    public List<Comment> getAllCommentsForLocation(long destId){
  //    System.out.println("Comment service destid.. " + destId );
      
      return destinationDAO.getCommentsForLocation(destId);
    }
              
    
    
    public List<Destination> getDestinationsForUser(User user) {
       // User loggedIn = userService.getCurrentUser();
    //    System.out.println("User nickname is " + user.getNickname());
        List<Destination> dest= (List<Destination>) user.getDestinations();
      //  System.out.println("Found destination " + dest.size());
        return dest;
    }
    
    
    public List<Destination> getNDestinations(int n) {
        //System.out.println("In get add destinations");
        return destinationDAO.getAllDestinations(0, n);
    }
    
    
    public List<Comment> getAllComments() {
    //    System.out.println("In get add comments");
        return destinationDAO.getAllComments(0, 2500);
    }
    
    public List<Comment> getNComments(int n) {
    //    System.out.println("In get add comments");
        return destinationDAO.getAllComments(0, n);
    }
    
    public Destination getDestination(long destId) {
     //   System.out.println("In get add comments");
        return destinationDAO.getDestination(destId);
    }
    
    public List<String> getImages(String search,int num) {
     //   System.out.println("In get getImges");
        
      FlickrSearch f=new FlickrSearch(search, num);
      String[] u = f.getURLs();
      List<String> urls =new ArrayList();
      for(int i=0; i<u.length; i++){
       //   System.out.println(" urls : " + u[i]);
          urls.add(u[i]);
          
      }
      //System.out.println("Size of images " + urls.size());
        return urls;
    }
    
    public List<String> getImages() {
        List<Destination> locations=getAllLocations();
    //    System.out.println("In get getImges");
        List<String> urls =new ArrayList();
        for (Iterator it = locations.iterator(); it.hasNext(); ) {
            
            Destination destination = (Destination)it.next();
            String n=destination.getName();
            n.replaceAll(" +", " OR ");
      //      System.out.println("Location name... " + destination.getName() );
            FlickrSearch f=new FlickrSearch(n, 1);
            String[] u=f.getURLs();
            if (u[0] !=null){
                urls.add(u[0]);
            }else{
                    urls.add("http://farm2.static.flickr.com/1194/529356033_dbdae392d2_m.jpg");
            }
            
        }
           
     
        return urls;
    }
   // getImages(String search);
    
/*
    public PostsList getForum(ForumTopic forumTopic, int start, int max) {
        if (forumTopic instanceof User) {
            User user = (User) forumTopic;
            return destinationDAO.getUserThreads(user.getId(), start, max);
        } else if (forumTopic instanceof School) {
            School school = (School) forumTopic;
            return destDAO.getSchoolThreads(school.getId(), start, max);
        } else if (forumTopic instanceof ForumPost) {
            ForumPost post = (ForumPost) forumTopic;
            return schoolDAO.getPostsForThread(post, start, max);
        } else if (forumTopic instanceof RecentForumPostTopic) {
            return schoolDAO.getRecentForumPosts(start, max);
        } else {
            throw new RuntimeException("Unknown forumTopic: "
                    + forumTopic);
        }
    }

    public List<SchoolPopularity> getPopularSchools() {
        List<SchoolPopularity> ranked = new LinkedList<SchoolPopularity>();
        for (School school : getTopSchools(0, 10)) {
            ranked.add(new SchoolPopularity(school, school
                    .getPopularityCounter()));
        }
        return ranked;
    }
*/
    public Destination getDestinationDetails(String destinationname) {

        Destination destination = destinationDAO.getDestinationFromName(destinationname);

   //     incrementSchoolPopularity(destination);

        return destination;
    }

  

    public List<Destination> getDestinationsStarting(String match, int start,
            int max) {
        return destinationDAO.getDestinationsMatching(match, start, max);
    }

    /**
     * Search for "match*" using searchService
     * 
     * @throws SiteException
     */
    public List<String> getDestinationStringsMatching(String match)
            throws SiteException {
   //     return searchService.searchForDestination(match);
        // return schoolDAO.getSchoolsMatching(match);
        return null;
    }
    
    public List<Comment> matchComment(String queryString){
        return null;
    }
/*
    public PostsList getSchoolThreads(long schoolID, int start, int max) {
        return schoolDAO.getSchoolThreads(schoolID, start, max);
    }

    public List<School> getTopSchools(int start, int max) {
        return schoolDAO.getAllSchools(start, max);
    }

    public List<User> getUsersInterestedIn(School school) {
        return schoolDAO.getUsersInterestedIn(school);
    }

    public List<ProcessType> matchProcessType(String queryString) {

        return schoolDAO.matchProcessType(queryString);
    }
*/
    /**
     * TODO protect?
     */
    public void save(Loadable loadable) {
        if (loadable instanceof User) {
            User user = (User) loadable;
            userService.save(user);
        } else {
            destinationDAO.save(loadable);
        }
    }

    @Required
    public void setDestinationDAO(DestinationDAO destinationDAO) {
        this.destinationDAO = destinationDAO;
    }

    @Required
    public void setSearchService(SearchService searchService) {
        this.searchService = searchService;
    }

    @Required
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

}
